﻿#define NOMINMAX
#include <windows.h>
#include <cmdline.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <climits>
#include <string>
#include <chrono> // 程序计时
#include <numbers>

#include "ColorSpace/ColorSpace.h" 
#include "ColorSpace/Comparison.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image/stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image/stb_image_write.h"
//#define STB_IMAGE_RESIZE_IMPLEMENTATION
//#include "stb_image/stb_image_resize2.h"

#include "structure.hpp"
#include "heightComressLine.hpp"
#include "./mapcolor/mapcolor_lab.h"
#include "./mapcolor/mapcolor3_lab.h"
#include "./mapcolor/mapcolor_rgb.h"
#include "./mapcolor/mapcolor3_rgb.h"

bool createDir(const std::string& dirPath);
bool writeFile(const std::string& filePath, const std::string& content);
std::string buildFillLine(const std::string& type, const std::vector<int>& pos1, const std::vector<int>& pos2);
std::string buildSetblockLine(const std::string&, const std::vector<int>&);
int get_delta_y(int x, int z, const std::string& light);
double rgb_plus(const ColorSpace::Rgb* rgb1, const ColorSpace::Rgb* rgb2);

static double limit255(double a) {
	if (a < 0) { return 0.0; }
	if (a > 255) { return 255.0; }
	return a;
}
static void COLOR_PRINT(std::string s, int color, bool middle = false)
{	
	if (middle) {
		HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
		CONSOLE_SCREEN_BUFFER_INFO bInfo;
		GetConsoleScreenBufferInfo(hOutput, &bInfo);//获取窗口长度
		int len = bInfo.dwSize.X / 2 - s.size() * 5 / 8;//空多少个格
		printf("\033[%dC", len);//光标右移
	}
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | color);
	std::cout << s << std::flush; 
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 7);
}

int main(int argc, char* argv[]) {
	std::cout << std::endl;
	COLOR_PRINT(".########..####.##.....##.########.##................###....########..########\n", 11, true);
	COLOR_PRINT(".##.....##..##...##...##..##.......##...............##.##...##.....##....##...\n", 11, true);
	COLOR_PRINT(".##.....##..##....##.##...##.......##..............##...##..##.....##....##...\n", 11, true);
	COLOR_PRINT(".########...##.....###....######...##.............##.....##.########.....##...\n", 11, true);
	COLOR_PRINT(".##.........##....##.##...##.......##.............#########.##...##......##...\n", 11, true);
	COLOR_PRINT(".##.........##...##...##..##.......##.............##.....##.##....##.....##...\n", 11, true);
	COLOR_PRINT(".##........####.##.....##.########.########.......##.....##.##.....##....##...\n", 11, true);
	std::cout << std::endl;
	COLOR_PRINT("**************************** MCBE 地图像素画生成程序 ****************************\n", 14, true);
	COLOR_PRINT("https://gitee.com/wn1027/mcbe-map_pixel_art    Author: Wn1027 | Qgroup: 311860068\n\n", 13, true);

	cmdline::parser theArgs;
	//theArgs.add<std::string>("imgFilePath", 'i', "图片路径", true);//, "D:/Work/Code/CPP/map_pixel_art/.img/f_128.jpg"
	theArgs.add<bool>("mcstructure", 's', "启用生成mcstructure", false, true);
	theArgs.add<bool>("mcfunction", 'f', "启用生成mcfunction", false, true);
	theArgs.add<bool>("preview", 'p', "启用生成预览图", false, true);
	theArgs.add<std::string>("structureDir", '\0', "mcstructure文件夹", false, ".\\structures\\");
	theArgs.add<std::string>("mcfunctionDir", '\0', "mcfunction文件夹", false, ".\\mcfunctions\\");
	theArgs.add<std::string>("previewDir", '\0', "预览图文件夹", false, ".\\preview\\");

	theArgs.add<std::string>("comparison", 'c', "色差算法(RGB、RGB+、CIE2000、CIE1976)", false, "RGB", cmdline::oneof<std::string>("RGB", "RGB+", "CIE2000", "CIE1976"));
	theArgs.add<bool>("3d", '\0', "启用立体生成", false, true);
	theArgs.add<bool>("alpha", '\0', "启用透明度(透明部分不放方块)", false, false);
	theArgs.add<bool>("dither_fs", 'd', "启用仿色抖动", false, true);
	theArgs.add<int>("dither_fs_strength", '\0', "仿色抖动强度 [>=16, 16为全仿色, 32为半仿色]", false, 16, cmdline::range(16, 65535));
	theArgs.add<int>("dither_strength", '\0', "随机抖动额外颜色数(0为不抖动) [0,1,2,3...20]", false, 0, cmdline::range(0, 20));
	theArgs.add<int>("dither_threshold", '\0', "随机抖动色差阈值[0~100]", false, 12, cmdline::range(0, 65535));
	theArgs.add<float>("dither_limit", '\0', "随机抖动幅度限制(默认75%偏差内,越小颜色越平滑)[0~1]", false, 0.75f, cmdline::range(0.0f, 1.0f));
	//theArgs.add<int>("width", 'w', "重设原图宽度", false, 0, cmdline::range(0, 4095));
	//theArgs.add<int>("height", 'h', "重设原图高度", false, 0, cmdline::range(0, 4095));
	//theArgs.parse_check(argc, argv);
	if (argc == 1 && !theArgs.parse(argc - 1, argv + 1)) {
		COLOR_PRINT(">> 生成之前请先使用工具将图片长宽缩小到128的倍数\n", 10);
		COLOR_PRINT(">> 此为命令行程序, 请在控制台指定参数运行: map_pixel_art.exe xxx.jpg [option]\n\n ", 10);
		std::cout << theArgs.usage() << std::endl;
		system("pause"); exit(1);
	}
	theArgs.parse_check(argc, argv);
	//std::filesystem::path imgFilePath = theArgs.get<std::string>("imgFilePath");
	std::filesystem::path imgFilePath = argv[1];
	std::filesystem::path structureDir = theArgs.get<std::string>("structureDir");
	std::filesystem::path previewDir = theArgs.get<std::string>("previewDir");
	std::filesystem::path mcfunctionDir = theArgs.get<std::string>("mcfunctionDir"); 
	const std::string Comparison = theArgs.get<std::string>("comparison");
	const bool EnablePreview = theArgs.get<bool>("preview");
	const bool EnableMcstructure = theArgs.get<bool>("mcstructure");
	const bool EnableMcfunction = theArgs.get<bool>("mcfunction");
	const bool EnableUneven = theArgs.get<bool>("3d");
	const bool EnableAlpha = theArgs.get<bool>("alpha");
	const bool EnableDitherFloyd = theArgs.get<bool>("dither_fs");
	//int Ow = theArgs.get<int>("width");
	//int Oh = theArgs.get<int>("height");
	const int Dither_fs_strength = theArgs.get<int>("dither_fs_strength");
	const int Dither_threshold = theArgs.get<int>("dither_threshold");
	const int Dither_strength = theArgs.get<int>("dither_strength");
	const float Dither_limit = theArgs.get<float>("dither_limit");
	std::string imgFileName = imgFilePath.filename().string();
	std::string imgName = imgFilePath.stem().string();
	std::string suffix = imgFilePath.extension().string();
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | 7);

	auto start = std::chrono::high_resolution_clock::now();

	// 加载图片
	int width, height, channels;
	unsigned char* img = stbi_load(imgFilePath.string().c_str(), &width, &height, &channels, 0);
	if (img == NULL) {
		std::cout << "图片路径无效或无法打开: " << imgFilePath.string() << std::endl;
		return 1;
	}
	std::cout << std::format("# 加载图片完成: {0} | {1} x {2}", imgFileName, width, height) << std::endl;

	// 重设尺寸
	/*if (Ow != 0 || Oh != 0) {
		unsigned char* newImg = (unsigned char*)malloc(static_cast<size_t>(Ow * Oh * 4));
		stbir_resize_uint8_srgb(img, width, height, 0, newImg, Ow, Oh, 0, STBIR_4CHANNEL);
		width = Ow;
		height = Oh;
		stbi_image_free(img);
		img = newImg;
		std::cout << std::format("# 重设图片尺寸: {0} x {1}", width, height) << std::endl;
	}*/

	// 计算地图画尺寸
	int size[2]{};
	size[0] = width / 128;
	size[1] = height / 128;
	if (width % 128 != 0) {
		size[0]++;
	}
	if (height % 128 != 0) {
		size[1]++;
	}
	std::cout << std::format("# 输出地图画尺寸: {0} x {1}", size[0], size[1]) << std::endl;
	std::cout << ">> 正在处理像素...请稍后..." << std::endl;

	// 定义变量
	const std::string FlatOrUneven = EnableUneven ? "3d" : "flat";
	const std::vector<MapColor_RGB>* mapcolor = EnableUneven ? mapcolor3_rgb : mapcolor_rgb;
	size_t mapcolor_size = mapcolor->size();

	unsigned char* img_preview_data = nullptr; // 预览图片数据
	if (EnablePreview) {
		img_preview_data = new unsigned char[size[0] * 128 * size[1] * 128 * channels](0);
	}
	

	// 像素生成
	struct StructPreData { int minIndex; int y; bool alpha = false; };
	std::vector<StructPreData> structPreDatas; // 存储每个像素的方块数据
	std::vector<std::vector<int>> delta_y_all(width, std::vector<int>(height)); // 存储相对高度
	for (int pIndex = 0; pIndex < width * height; pIndex++) {
		int h = pIndex / width;
		int w = pIndex % width;
		const bool isAlphaPixel = channels == 4 && img[channels * pIndex + 3] == 0;

		int minIndex = -1; // 选取的最小色差索引
		static bool dithering_seed = true;
		std::vector<int> dither_index; // 阈值内的颜色索引

		// 颜色比较
		if (!isAlphaPixel) {
			ColorSpace::Rgb rgb(
				img[channels * pIndex + 0],
				img[channels * pIndex + 1],
				img[channels * pIndex + 2]
			);
			ColorSpace::Lab lab;
			rgb.To<ColorSpace::Lab>(&lab);

			std::vector<double> colorCieResArray; // 存储64个计算好的色差
			std::vector<double> colorCieResArray2; // 排序色差
			for (auto& element : *mapcolor) {
				if (EnableAlpha && h != 0 && delta_y_all[w][h - 1] == INT_MIN && element.shades != "HIGH") {
					colorCieResArray.emplace_back(1000);
					colorCieResArray2.emplace_back(1000); // 色差取个超大的值，表示取不到该颜色
					continue; // z-1是透明像素，说明此像素悬空，只能在高亮色中选取
				}
				if (EnableUneven && h == 0 && element.shades != "HIGH") {
					colorCieResArray.emplace_back(1000000000.0);
					colorCieResArray2.emplace_back(1000000000.0);
					continue;
				}
				double cieRes;

				ColorSpace::Rgb rgb_palette(
					element.r,
					element.g,
					element.b
				);

				if (Comparison == "CIE2000") {
					cieRes = ColorSpace::Cie2000Comparison::Compare(&rgb, &rgb_palette);
				}
				else if (Comparison == "CIE1976") {
					cieRes = ColorSpace::Cie1976Comparison::Compare(&rgb, &rgb_palette);
				}
				else if (Comparison == "RGB+") {
					cieRes = rgb_plus(&rgb, &rgb_palette);
				}
				else {
					cieRes = ColorSpace::EuclideanComparison::Compare(&rgb, &rgb_palette);
				}
				colorCieResArray.emplace_back(cieRes);
				colorCieResArray2.emplace_back(cieRes);
			}
			std::sort(colorCieResArray2.begin(), colorCieResArray2.end());
			// 打印所有色差
			/*if (h == 23 && w == 43) {
				for (int k = 0; k < mapcolor_size; k++) {
					std::cout << colorCieResArray2[k] << "; ";
				}
				std::cout << std::endl;
			}*/


			// 添加阈值内颜色索引
			for (int k = 0; k < colorCieResArray2.size(); k++) {
				if (dither_index.size() == 0) {
					dither_index.emplace_back(k);
				}
				else if (colorCieResArray2[k] <= Dither_threshold && dither_index.size() <= Dither_strength) {
					if ((colorCieResArray2[k] - colorCieResArray2[0]) < Dither_threshold * Dither_limit) { // 如果与首选色的偏差超过设定阈值的75%, 则不会添加该颜色
						dither_index.emplace_back(k);
					}
				}
				else {
					break;
				}
			}
			// 颜色抖动
			int order = rand() % dither_index.size();
			order = dithering_seed ? order : 0;
			for (int k = 0; k < mapcolor_size; k++) {
				if (colorCieResArray2[dither_index[order]] == colorCieResArray[k]) {
					minIndex = k;
					break;
				}
			}
			dithering_seed = !dithering_seed;
			if (w == 127) { dithering_seed = !dithering_seed; }


			// 误差扩散
			if (EnableDitherFloyd && !(w == 0 || h == 0 || w == width - 1 || h == height - 1)) {
				double quant_error_r = img[channels * pIndex + 0] - (*mapcolor)[minIndex].r;
				double quant_error_g = img[channels * pIndex + 1] - (*mapcolor)[minIndex].g;
				double quant_error_b = img[channels * pIndex + 2] - (*mapcolor)[minIndex].b;
				img[channels * (pIndex + 1) + 0] = limit255(img[channels * (pIndex + 1) + 0] + (quant_error_r * 7 / Dither_fs_strength));
				img[channels * (pIndex + 1) + 1] = limit255(img[channels * (pIndex + 1) + 1] + (quant_error_g * 7 / Dither_fs_strength));
				img[channels * (pIndex + 1) + 2] = limit255(img[channels * (pIndex + 1) + 2] + (quant_error_b * 7 / Dither_fs_strength));
				img[channels * (pIndex + width - 1) + 0] = limit255(img[channels * (pIndex + width - 1) + 0] + (quant_error_r * 3 / Dither_fs_strength));
				img[channels * (pIndex + width - 1) + 1] = limit255(img[channels * (pIndex + width - 1) + 1] + (quant_error_g * 3 / Dither_fs_strength));
				img[channels * (pIndex + width - 1) + 2] = limit255(img[channels * (pIndex + width - 1) + 2] + (quant_error_b * 3 / Dither_fs_strength));
				img[channels * (pIndex + width + 0) + 0] = limit255(img[channels * (pIndex + width + 0) + 0] + (quant_error_r * 5 / Dither_fs_strength));
				img[channels * (pIndex + width + 0) + 1] = limit255(img[channels * (pIndex + width + 0) + 1] + (quant_error_g * 5 / Dither_fs_strength));
				img[channels * (pIndex + width + 0) + 2] = limit255(img[channels * (pIndex + width + 0) + 2] + (quant_error_b * 5 / Dither_fs_strength));
				img[channels * (pIndex + width + 1) + 0] = limit255(img[channels * (pIndex + width + 1) + 0] + (quant_error_r * 1 / Dither_fs_strength));
				img[channels * (pIndex + width + 1) + 1] = limit255(img[channels * (pIndex + width + 1) + 1] + (quant_error_g * 1 / Dither_fs_strength));
				img[channels * (pIndex + width + 1) + 2] = limit255(img[channels * (pIndex + width + 1) + 2] + (quant_error_b * 1 / Dither_fs_strength));
			}
		}
		else {
			minIndex = 0;
		}

		// 记录delta_y
		if (EnableUneven) {
			if (isAlphaPixel) {
				delta_y_all[w][h] = INT_MIN; // 标记透明像素
			}
			else if (h == 0) {
				delta_y_all[w][h] = 0;
			}else {
				delta_y_all[w][h] = get_delta_y(w, h, (*mapcolor)[minIndex].shades);
			}
		}

		// 透明像素无方块
		structPreDatas.emplace_back(StructPreData{ .minIndex = minIndex, .y = 0, .alpha = isAlphaPixel}); 
	}


	// 高度压缩
	int map_height = 1;
	if (EnableUneven) {
		for (int w = 0; w < width; w++) {
			std::vector<int> heightRes = heightCompressLine(delta_y_all[w]);
			if (heightRes.back()+1 > map_height) {
				map_height = heightRes.back()+1;
			}
			heightRes.pop_back(); // 弹出最后用于记录最大高度的值
			for (int h = 0; h < heightRes.size(); h++) {
				int pIndex = h * width + w;
				structPreDatas[pIndex].y = heightRes[h];
			}
		}
		std::cout << ">> 3D 生成高度: " << map_height << std::endl;
	}

	
	// 128分割写入
	for (int j = 0; j < size[1]; j++) {
		for (int i = 0; i < size[0]; i++) {
			mcstructure::Structure newStructure({ 128, map_height , 128 }); // 输出mcstructure
			mcstructure::Structure emptyStructure({ 128, map_height , 128 }); // 输出mcstructure
			std::vector<std::string> mcfunctions_content = { "" }; // 输出mcfunction
			int cmdNum = 0;
			int nowFileIndex = 0;

			for (int h = 0; h < 128; h++) {
				std::string lastBlockType = ""; // 平面生成时记录上个w位置的类型
				int lastW = 0; // 平面生成时记录上个w位置
				int lastY = -999;

				for (int w = 0; w < 128; w++) {
					// 白边部分
					if ((1 + w + (128 * i)) > width || (1 + h + (128 * j)) > height) {						
						if (EnableAlpha) {
							continue;
						}

						if (EnableMcstructure) {
							newStructure.set_block((*mapcolor)[0].type, w, 0 ,h);
						}

						if (EnableMcfunction) {
							mcfunctions_content[nowFileIndex] += buildSetblockLine((*mapcolor)[0].type, { w, 0 ,h });
						}
					}

					// 图片部分
					else {
						unsigned int pIndex = (j * 128 + h) * width + (i * 128) + w; // 在数据中的索引
						unsigned int dataIndex = channels * ((j * 128 + h) * width + (i * 128) + w); // 在数据中的索引

						// 透明像素不写入数据
						if (EnableAlpha && structPreDatas[pIndex].alpha) {
							continue; 
						}

						int minIndex = structPreDatas[pIndex].minIndex;
						int y = structPreDatas[pIndex].y;

						// 写入structure
						if (EnableMcstructure) {
							newStructure.set_block((*mapcolor)[minIndex].type, w, y, h);
						}

						// 写入function
						if (EnableMcfunction) {
							// 每行第一个方块给判断条件赋初值
							if (lastBlockType == "") {
								lastBlockType = (*mapcolor)[minIndex].type;
							}
							if (lastY == -999) {
								lastY = y;
							}

							// 满10000行命令更换文件
							if (cmdNum > 9998) {
								mcfunctions_content.emplace_back("");
								nowFileIndex++;
								cmdNum = 0;
							}
							
							// 压缩fill
							if ((!EnableUneven && ((*mapcolor)[minIndex].type != lastBlockType || w == 127)) || (EnableUneven && ((*mapcolor)[minIndex].type != lastBlockType || y != lastY || w == 127))) {
								// 只放一个方块
								if (w - lastW == 1) {
									mcfunctions_content[nowFileIndex] += buildSetblockLine(lastBlockType, { lastW, lastY, h}); // 放置上一个方块
									if (w == 127) {
										mcfunctions_content[nowFileIndex] += buildSetblockLine(lastBlockType, { w, y, h });
										cmdNum++; // 额外放置最后方块
									}
								}

								// 放置fill
								else {
									mcfunctions_content[nowFileIndex] += buildFillLine(lastBlockType, { lastW, lastY, h }, { w - 1, lastY, h }); // 放置到上一个方块
									if (w == 127) {
										// 如果这里w++ , 后面会指针越界，导致程序无报错但卡在最后delete[] img_preview_data
										mcfunctions_content[nowFileIndex] += buildSetblockLine(lastBlockType, { w, y, h });
										cmdNum++; // 额外放置最后方块
									}
								}
								cmdNum++;
								lastBlockType = (*mapcolor)[minIndex].type;
								lastW = w;
								lastY = y;
							}
						}
						
						// 写入像素到预览图片
						if (EnablePreview) {
							/*ColorSpace::Lab blocklab(
								(*mapcolor)[minIndex].l,
								(*mapcolor)[minIndex].a,
								(*mapcolor)[minIndex].b
							);
							ColorSpace::Rgb blockrgb;
							blocklab.To<ColorSpace::Rgb>(&blockrgb);*/
							img_preview_data[dataIndex + 0] = static_cast<unsigned char>((*mapcolor)[minIndex].r);
							img_preview_data[dataIndex + 1] = static_cast<unsigned char>((*mapcolor)[minIndex].g);
							img_preview_data[dataIndex + 2] = static_cast<unsigned char>((*mapcolor)[minIndex].b);
							if (channels == 4) {
								img_preview_data[dataIndex + 3] = img[dataIndex + 3];
							}
						}
					}
				}
			}
			
			if (EnableMcstructure) {
				createDir((structureDir / imgName).string());
				emptyStructure.dump(structureDir / (imgName + "/" + imgName + "_" + FlatOrUneven + "_dither_" + std::to_string(Dither_strength) + "_" + std::to_string(i) + "_" + std::to_string(j) + "_empty.mcstructure"));
				newStructure.dump(structureDir / (imgName + "/" + imgName + "_" + FlatOrUneven + "_dither_" + std::to_string(Dither_strength) + "_" + std::to_string(i) + "_" + std::to_string(j) + ".mcstructure"));
				std::cout << "写入structure: " + std::to_string(i) + "_" + std::to_string(j) << std::endl;
			}

			if (EnableMcfunction) {
				createDir((mcfunctionDir / imgName).string());
				for (int k = 0; k < mcfunctions_content.size(); k++) {
					writeFile((mcfunctionDir / (imgName + "\\" + imgName + "_" + FlatOrUneven + "_dither_" + std::to_string(Dither_strength) + "_" + std::to_string(i) + "_" + std::to_string(j) + "-" + std::to_string(k) + ".mcfunction")).string(), mcfunctions_content[k]);
				}
				std::cout << "写入mcfunction: " + std::to_string(i) + "_" + std::to_string(j) << std::endl;
			}
		}
	}


	// 程序结束 写入预览图片
	if (EnablePreview) {
		createDir((previewDir / imgName).string());
		//stbi_write_jpg(resultPath.c_str(), width, height, channels, img, 100);
		stbi_write_png(((previewDir / (imgName + "\\" + imgName + "_" + FlatOrUneven + "_dither_" + std::to_string(Dither_strength) + suffix)).string()).c_str(), width, height, channels, img_preview_data, 0);
		//free(img_preview_data);
		delete[] img_preview_data;
		std::cout << "写入图片: " + imgName + "_" + FlatOrUneven + "_dither_" + std::to_string(Dither_strength) + suffix << std::endl;
	}
	
	// 程序结束 释放内存
	stbi_image_free(img);
	delete mapcolor3_lab;
	delete mapcolor_lab;

	std::cout << std::endl;
	std::cout << "以下是一段JavaScript函数, 用于获取当前128地图的起始坐标，请复制到浏览器F12控制台执行（输入x，z坐标）" << std::endl;
	std::cout << "function pos(x, z){return `/tp ${Math.floor((x-64) / 128) * 128 + 64} ~ ${Math.floor((z-64) / 128) * 128 + 64}`;}" << std::endl;
	
	auto stop = std::chrono::high_resolution_clock::now();
	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
	std::cout << "\nElapsed time: " << (double)duration/(double)1000 << " s\n";
	return 0;
}

bool createDir(const std::string& dirPath) {
	if (!std::filesystem::exists(dirPath)) {
		if (!std::filesystem::create_directories(dirPath)) {
			std::cerr << "无法创建目录: " << dirPath << std::endl;
			return false;
		}
		return true;
	}
	return true;
}

bool writeFile(const std::string& filePath, const std::string& content) {
	std::ofstream out1File(filePath);
	if (!out1File.is_open()) {
		std::cerr << "无法打开文件 " + filePath << std::endl;
		return false;
	}
	out1File << content << std::endl;
	out1File.close();
	return true;
}

std::string buildSetblockLine(const std::string& type, const std::vector<int>& pos) {
	return "setblock ~" + std::to_string(pos[0]) + " ~" + std::to_string(pos[1]) + " ~" + std::to_string(pos[2]) + " " + type + "\n";
}

std::string buildFillLine(const std::string& type, const std::vector<int>& pos1, const std::vector<int>& pos2) {
	return "fill ~" + std::to_string(pos1[0]) + " ~" + std::to_string(pos1[1]) + " ~" + std::to_string(pos1[2]) + " ~" + std::to_string(pos2[0]) + " ~" + std::to_string(pos2[1]) + " ~" + std::to_string(pos2[2]) + " " + type + "\n";
}


// （x奇偶性，z奇偶性，光强）=> 相对于-z方向方块的y值
/*
	地图方向
	 ——> x
	|
	Z
*/

int get_delta_y(int x, int z, const std::string& light) {
	std::string isOdd_str = std::to_string(x%2) + std::to_string(z%2) + light;
	if (isOdd_str == "00LOW") {
		return -1;
	} else if (isOdd_str == "00HIGH") {
		return 2;
	} else if (isOdd_str == "01LOW") {
		return -2;
	} else if (isOdd_str == "01HIGH") {
		return 1;
	} else if (isOdd_str == "10LOW") {
		return -2;
	} else if (isOdd_str == "10HIGH") {
		return 1;
	} else if (isOdd_str == "11LOW") {
		return -1;
	} else if (isOdd_str == "11HIGH") {
		return 2;
	} else {
		return 0;
	}
}


double rgb_plus(const ColorSpace::Rgb* rgb1, const ColorSpace::Rgb* rgb2) {
	// https://www.cnki.com.cn/Article/CJFDTotal-JSGG201006045.htm
	double r1 = rgb1->r;
	double g1 = rgb1->g;
	double b1 = rgb1->b;
	double r2 = rgb2->r;
	double g2 = rgb2->g;
	double b2 = rgb2->b;
	double W_r = 3;
	double W_g = 4;
	double W_b = 2;
	double thre = 1e-10f;
	double averageAllChanel = (r1 + g1 + b1 + r2 + g2 + b2) / 3 + thre;
	double S_r = std::min(1.0, (r1 + r2) / averageAllChanel);
	double S_g = std::min(1.0, (g1 + g2) / averageAllChanel);
	double S_b = std::min(1.0, (b1 + b2) / averageAllChanel);
	double theta = 2 / std::numbers::pi * std::acos((r1 * r2 + g1 * g2 + b1 * b2) / std::sqrt((pow(r1, 2) + pow(g1, 2) + pow(b1, 2)) * (pow(r2, 2) + pow(g2, 2) + pow(b2, 2)) + thre));
	double S_theta_r = pow(S_r, 2) * (abs(r1 - r2) / (r1 + r2)) / (abs(r1 - r2) / (r1 + r2 + thre) + abs(g1 - g2) / (g1 + g2 + thre) + abs(b1 - b2) / (b1 + b2 + thre));
	double S_theta_g = pow(S_g, 2) * (abs(g1 - g2) / (g1 + g2)) / (abs(r1 - r2) / (r1 + r2 + thre) + abs(g1 - g2) / (g1 + g2 + thre) + abs(b1 - b2) / (b1 + b2 + thre));
	double S_theta_b = pow(S_b, 2) * (abs(b1 - b2) / (b1 + b2)) / (abs(r1 - r2) / (r1 + r2 + thre) + abs(g1 - g2) / (g1 + g2 + thre) + abs(b1 - b2) / (b1 + b2 + thre));
	double S_theta = S_theta_r + S_theta_g + S_theta_b;
	double S_ratio = std::max({ 1.0, r2, g1, g2, b1, b2 }) / 255;
	double dist = std::sqrt((pow(S_r,2) * W_r * pow((r1 - r2),2) + pow(S_g,2) * W_g * pow((g1 - g2),2) + pow(S_b,2) * W_b * pow((b1 - b2),2)) / (pow(255,2) * (W_r + W_g + W_b) + thre) + S_theta * S_ratio * pow(theta,2));
	return dist;
}